package com.nuoye.camera2studydemo.base;

import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;

import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.listener.OnItemClickListener;
import com.nuoye.camera2studydemo.ChickConsumer;
import com.nuoye.camera2studydemo.R;
import com.nuoye.camera2studydemo.adapter.Camera2ControlAdapter;
import com.nuoye.camera2studydemo.databinding.FragmentCameraPlayerBinding;

import java.util.ArrayList;
import java.util.List;

/**
 * 相机基础控制类。
 */
@SuppressLint("NewApi")
public abstract class Camera2ControlFragment extends Fragment {
    String TAG = "Control";
    protected FragmentCameraPlayerBinding binding;
    protected Camera2ControlAdapter controlAdapter = new Camera2ControlAdapter();
    protected HandlerThread cameraThread;
    protected Handler cameraHandler;
    protected CameraManager cameraManager;
    protected CameraDevice mCameraDevice;
    protected CameraCaptureSession mSession;
    protected CaptureRequest.Builder builder = null;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_camera_player, container, false);
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        binding.recyclerControl.setLayoutManager(new GridLayoutManager(getContext(), 4));
        binding.recyclerControl.setAdapter(controlAdapter);
        controlAdapter.setNewInstance(getControls());
        binding.texture.getHolder().addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(@NonNull SurfaceHolder holder) {
                initCamera2();
            }

            @Override
            public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(@NonNull SurfaceHolder holder) {

            }
        });

    }


    @SuppressLint("MissingPermission")
    private void initCamera2() {
        cameraThread = new HandlerThread("cameraThread");
        cameraThread.start();
        cameraHandler = new Handler(cameraThread.getLooper());
        cameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
        // 添加监听。
        /**
         * > 如果在调用打开相机之前开启闪光灯，后调用打开相机，闪光灯会关闭。
         * 第一次调用打开相机
         * * onTorchModeUnavailable闪光灯不可用 : 0
         * * onCameraUnavailable相机不可用: 0
         * * onOpened 打开相机: 0
         * 第2次调用打开相机
         * * onDisconnected 相机断开: 0
         * * onTorchModeChanged 闪光灯模式已经更改 : 0  false
         * * onCameraAvailable 可用的相机: 0
         * * onTorchModeUnavailable闪光灯不可用 : 0
         * * onCameraUnavailable相机不可用: 0
         * * onOpened 打开相机: 0
         */
        cameraManager.registerAvailabilityCallback(new CameraManager.AvailabilityCallback() {
            @Override
            public void onCameraAvailable(@NonNull String cameraId) {
                super.onCameraAvailable(cameraId);
                Log.e(TAG, "onCameraAvailable 可用的相机: " + cameraId);
            }

            @Override
            public void onCameraUnavailable(@NonNull String cameraId) {
                super.onCameraUnavailable(cameraId);
                Log.e(TAG, "onCameraUnavailable相机不可用: " + cameraId);
            }

            @Override
            public void onCameraAccessPrioritiesChanged() {
                super.onCameraAccessPrioritiesChanged();
                Log.e(TAG, "onCameraAccessPrioritiesChanged 关于相机访问优先级已更改: ");
            }
        }, cameraHandler);
        cameraManager.registerTorchCallback(new CameraManager.TorchCallback() {
            @Override
            public void onTorchModeUnavailable(@NonNull String cameraId) {
                super.onTorchModeUnavailable(cameraId);
                Log.e(TAG, "onTorchModeUnavailable闪光灯不可用 : " + cameraId);
            }

            @Override
            public void onTorchModeChanged(@NonNull String cameraId, boolean enabled) {
                super.onTorchModeChanged(cameraId, enabled);
                Log.e(TAG, "onTorchModeChanged 闪光灯模式已经更改 : " + cameraId + "  " + enabled);
            }
        }, cameraHandler);
        // 打开摄像头。
        try {
            cameraManager.openCamera("0", new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice cameraDevice) {
                    Log.e(TAG, "onOpened 打开相机: " + cameraDevice.getId());
                    mCameraDevice = cameraDevice;
                    createCaptureSession();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice cameraDevice) {
                    Log.e(TAG, "onDisconnected 相机断开: " + cameraDevice.getId());
                }

                @Override
                public void onError(@NonNull CameraDevice cameraDevice, int i) {
                    Log.e(TAG, "onDisconnected 发生了错误: " + cameraDevice.getId() + "  " + i);
                }
            }, cameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 这个地方是可以被重写的。
     */
    protected void createCaptureSession() {
        Surface surface = binding.texture.getHolder().getSurface();
        List<Surface> targets = new ArrayList<>();
        // 如果要录制的或者分析，或者美化的话，这里需要添加启动输出通道。
        targets.add(surface);
        try {
            mCameraDevice.createCaptureSession(targets, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mSession = session;
                    try {
                        builder = session.getDevice().createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
                        builder.addTarget(binding.texture.getHolder().getSurface());
                        session.setRepeatingRequest(builder.build(), null, cameraHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {

                }
            }, cameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    protected abstract List<ChickConsumer> getControls();

    @Override
    public void onDestroy() {
        super.onDestroy();
        cameraThread.quitSafely();
        try {
            cameraThread.join();
            mCameraDevice.close();
        } catch (Exception e) {

        }
    }

    protected CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() {
        @Override
        public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
            super.onCaptureStarted(session, request, timestamp, frameNumber);
            Log.e(TAG, "onCaptureStarted 开始: " );
        }

        @Override
        public void onCaptureBufferLost(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull Surface target, long frameNumber) {
            super.onCaptureBufferLost(session, request, target, frameNumber);
            Log.e(TAG, "onCaptureBufferLost: " );
        }

        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            super.onCaptureCompleted(session, request, result);
            Log.e(TAG, "onCaptureCompleted: " );
        }

        @Override
        public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
            super.onCaptureFailed(session, request, failure);
            Log.e(TAG, "onCaptureFailed: " );
        }

        @Override
        public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
            super.onCaptureProgressed(session, request, partialResult);
            Log.e(TAG, "onCaptureProgressed: " );
        }

        @Override
        public void onCaptureSequenceAborted(@NonNull CameraCaptureSession session, int sequenceId) {
            super.onCaptureSequenceAborted(session, sequenceId);
            Log.e(TAG, "onCaptureSequenceAborted: " );
        }

        @Override
        public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) {
            super.onCaptureSequenceCompleted(session, sequenceId, frameNumber);
            Log.e(TAG, "onCaptureSequenceCompleted: " );
        }

    };

    /**
     * 请求session
     */
    public void applyRequest(){
        try {
            mSession.setRepeatingRequest(builder.build(), null, cameraHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
}
